
import
	tango.io.Stdout,
	tango.io.device.File,
	dwt.all ,
	dwt.scintilla.Scintilla ;

void main(){

	auto de	= new Demo;
	de.run;
}

class Demo{
	static char[] KeyWords = 
		"and and_eq asm auto bitand bitor bool break "
		"case catch char class compl const const_cast continue "
		"default delete do double dynamic_cast else enum explicit export extern false float for "
		"friend goto if inline int long mutable namespace new not not_eq "
		"operator or or_eq private protected public "
		"register reinterpret_cast return short signed sizeof static static_cast struct switch "
		"template this throw true try typedef typeid typename union unsigned using "
		"virtual void volatile wchar_t while xor xor_eq ";
  	static public int rgb (int r, int g, int b) {
		return (r & 0xff) | ((g & 0xff) << 8) | ((b & 0xff) << 16);
	}
	
	Display	display;
	Shell		shell;
	Menu		menubar;
	Scintilla	scintilla;
	int		BackGroundColor = 0xffffff;
	
	this(){
		display = new Display();
		shell	= new Shell(display);
		shell.setSize(new Point(560, 420));
		shell.setText("Scintilla in DWT");
		shell.setLayout(new FillLayout());
		scintilla = new Scintilla(shell, DWT.BORDER|DWT.H_SCROLL|DWT.V_SCROLL);
		
		
		with(scintilla){
			
			clearCmdKey('A' + (SCMOD_CTRL << 16));
			clearCmdKey('C' + (SCMOD_CTRL << 16));
			clearCmdKey('D' + (SCMOD_CTRL << 16));
			clearCmdKey('S' + (SCMOD_CTRL << 16));
			
			
			setLexer(SCLEX_D);
			setKeyWords(0, KeyWords);
			setAStyle(STYLE_DEFAULT, 0, BackGroundColor, 11, "Courier New");
			styleClearAll();
			setAStyle(SCE_D_DEFAULT, rgb(0, 0, 0));
			setAStyle(SCE_D_COMMENT, rgb(0, 0x80, 0));
			setAStyle(SCE_D_COMMENTLINE, rgb(0, 0x80, 0));
			setAStyle(SCE_D_COMMENTDOC, rgb(0, 0x80, 0));
			setAStyle(SCE_D_COMMENTLINEDOC, rgb(0, 0x80, 0));
			setAStyle(SCE_D_COMMENTDOCKEYWORD, rgb(0, 0x80, 0));
			setAStyle(SCE_D_COMMENTDOCKEYWORDERROR, rgb(0, 0x80, 0));
			setAStyle(SCE_D_NUMBER, rgb(0, 0x80, 0x80));
			setAStyle(SCE_D_WORD, rgb(0, 0, 0xff));
			styleSetBold(SCE_D_WORD, 1);
			setAStyle(SCE_D_STRING, rgb(0x80, 0, 0x80));
			setAStyle(SCE_D_IDENTIFIER, rgb(0, 0, 0));
			setAStyle(SCE_D_OPERATOR, rgb(0x80, 0x80, 0));
			setAStyle(SCE_D_STRINGEOL, rgb(0x80, 0x80, 0xf0));
	
			setMarginWidthN(2, 16);
			setFoldFlags(16);
			setMarginSensitiveN(2, true);
			setMarginTypeN(2, SC_MARGIN_SYMBOL);
			setMarginMaskN(2, SC_MASK_FOLDERS);
			setProperty("fold", "1");
			setProperty("fold.html", "1");
			setProperty("fold.html.preprocessor", "1");
			setProperty("fold.comment", "1");
			setProperty("fold.at.else", "1");
			setProperty("fold.flags", "1");
			setProperty("fold.preprocessor", "1");
			setProperty("styling.within.preprocessor", "1");
			
			//setProperty("character.set", "134");=
	
			// set the backgroundcolor of brace highlights
			styleSetBack(STYLE_BRACELIGHT, rgb(0,255,0));
			styleSetFore(STYLE_BRACELIGHT, rgb(255,0,0));
			styleSetBold(STYLE_BRACELIGHT, 1);

			// setup markers
			int white = rgb(255,255,255);
			int grey  = rgb(128,128,128);
			
			defineMarker(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS, white, grey);
			defineMarker(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS, white, grey);
			defineMarker(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE, white, grey);
			defineMarker(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER, white, grey);
			defineMarker(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED, white, grey);
			defineMarker(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED, white, grey);
			defineMarker(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER, white, grey);
			
			
			// setup auto completion
			autoCSetSeparator(10); //Use a separator of line feed
			// setup call tips
			setMouseDwellTime(1000);
			// High light current line
			setCaretLineVisible(true);
		}
		
		
		
		scintilla.handleNotify(cast(void*) this, SCN_UPDATEUI, &onNotify);
		scintilla.handleNotify(cast(void*) this, SCN_MARGINCLICK, &onMarginClick);
		scintilla.handleNotify(cast(void*) this,  SCN_CHARADDED, &onCharAdded);
		addMenu();
	}
	
	void onCharAdded(void* data, SCNotification* scn){
		auto self		= cast( Demo ) data;
		int ch		= scn.ch;
		const boolean 	SETTING_AUTOINDENT = true;
		int INDENT		= 8 ;
		
		int fl			= (ch=='\n') != 0 ;
		
		/*
		if(SETTING_AUTOINDENT && (fl || ch=='}'))
		{
			int curline=getCurrentLineNumber();
			int identpos=getLineIndentPosition(curline);
			int curpos=getCurrentPos();
			if((fl && identpos==curpos) || (ch=='}' && identpos==getLineEndPosition(curline)-1))
			{
				int lastline=curline-1;
				int previ=getLineIndentation(lastline);
				int indent=previ;
				if(getLineEndPosition(lastline)==getLineIndentPosition(lastline)) setLineIndentation(lastline,0);
				int c=getCharAt(getLineEndPosition(lastline)-1);
				if(fl && '{' && '{'==c) indent=previ+INDENT;
				else if(ch=='}') indent=getLineIndentation(curline)-INDENT;//getlastindentopen(lastline);
				//else if(m_template.settings.autoindentendofstatement && m_template.settings.autoindentendofstatement!=c) indent=getlastindentopen(lastline)+(INDENT*2);
		
				setLineIndentation(curline,indent);
				int pos=getLineIndentPosition(curline);
				if(ch=='}') pos++;
				setSearchPolicy();
				gotoPos(pos);
				setDefaultPolicy();
				// m_lastpos=pos;
				// m_parent.UpdateMenu_Editor(this,1,0,0);
			}
			// else m_lastpos=-1;
		}
		*/
	}
	
	void onNotify(void* data, SCNotification* scn){
		auto self	= cast( Demo ) data;
		uint lStart	= self.scintilla.getCurrentPos() ;
		uint lEnd	= self.scintilla.braceMatch(lStart - 1) ;
		if (lEnd >= 0)
			self.scintilla.braceHighlight(lStart - 1, lEnd);
		else
			self.scintilla.braceHighlight(-1, -1);
	}

	void onMarginClick(void* data, SCNotification* scn) {
		auto self	= cast( Demo ) data;
		MessageBox.showMessage("onMarginClick", "Alert", shell);
	}
	
	void defineMarker(int marker, int markerType, int fore, int back){
		scintilla.markerDefine(marker, markerType);
		scintilla.markerSetFore(marker, fore);
		scintilla.markerSetBack(marker, back);
	}
	
	void setAStyle(int style, int fore, int back = -1, int size = -1,  char[] face = null){
		if(back == -1)
			back = BackGroundColor;
		scintilla.styleSetFore(style, fore);
		scintilla.styleSetBack(style, back);
		if (size >= 1)
			scintilla.styleSetSize(style, size);
		if (face) 
			scintilla.styleSetFont(style, face);
	}
	
	void run(){
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) display.sleep();
		}
		display.dispose();
	}
	
	void addMenu(){
		Menu menubar = new Menu(shell, DWT.BAR);
		shell.setMenuBar(menubar);
		
		MenuItem fileMenuItem = new MenuItem(menubar, DWT.CASCADE);
		fileMenuItem.setText("&File");
		Menu menu = new Menu(fileMenuItem);
		fileMenuItem.setMenu(menu);

		with(  new MenuItem(menu, DWT.PUSH) ){
			setText("&Open");
			addListener(DWT.Selection, new class(this) Listener {
				private Demo _self ;
				public this(Demo _demo){
					this._self	= _demo;
				}
				public void handleEvent(Event e) {
					Stdout.formatln("{}	scintilla:{}", __LINE__, cast(void*) _self.scintilla);
					auto FileDialog dlg	= new FileDialog(_self.shell, DWT.OPEN);
					char[][] a;
					a ~= "*.c;*.cpp;*.h;*.txt;*.d; *.php; *.phtml; *.php5";
					a ~= "*.*";
					dlg.setFilterExtensions(a);
					char[] fullpath = dlg.open();
					if(fullpath !is null){
						try{
							_self.scintilla.clearAll();
							_self.scintilla.setCodePage(SC_CP_UTF8);
							_self.scintilla.setProperty("code.page", "65001");
							_self.scintilla.addText( cast(char[]) File.get(fullpath) );
							_self.shell.setText("Scintilla in DWT  -  " ~ fullpath[]);
						}catch(Exception e){
							MessageBox.showMsg(e.toString(), "Exception", _self.shell, DWT.OK|DWT.ICON_ERROR);
						}
					}
				}
		    });
		}
		

	}
	
}
